/**
 * @fileoverview HQ AJAX类
 * @author zhang jianbin
 * @version 1.0
 */
/**
 * @fileOverview 各种通信器
 */
/**
 * XMLHttpRequest通信器类
 * @class HQ.ajax
 * @constructor
 * @param {String} actionURI 请求地址
 * @param {String} [cname] 对象实体的索引名，默认是"_ajaxInstence_n"，n为序号
 * @param {String} [method] 发送方式，除非指明get，否则全部为post
 * @param {Object} [data] hashTable形式的字典
 * @param {Boolean} [isAsync] 是否异步，除非指明同步false,否则全部为异步true
 */
HQ.ajax = function(actionURL, cname, method, data, isAsync, nocache){
	if (!isURL(actionURL)) {
		rt.error("error actionURL -> {0:Q} in HQ.ajax construct!", actionURL);
		return null;
	}
	if (!isString(cname)) {
		cname = "_ajaxInstence_" + (HQ.ajax.counter + 1);
	}
	var prot;
	if (HQ.ajax.instance[cname] instanceof HQ.ajax) {
		prot = HQ.ajax.instance[cname];
	} else {
		prot = (HQ.ajax.instance[cname] = this);
		HQ.ajax.counter++;
	}
	prot._name = cname;
	prot._nc = !!nocache;
	prot._method = (!isString(method) || method.toUpperCase() != "GET") ? "POST" : (method = "GET");
	prot._isAsync = (!(isAsync === false)) ? true : isAsync;
	prot._uri = actionURL;
	prot._data = (isHashMap(data) || typeof(data)=='string') ? data : null;
	prot._sender = null;
	prot._isHeaderSetted = false;
	
	//对外的接口
	/**
	 * 当成功回调时,跨域请求和同域请求返回的数据不一样
	 * @event
	 */
	prot.onSuccess = HQ.emptyFn;
	
	/**
	 * 当错误回调时,跨域请求和同域请求返回的数据不一样
	 * @event
	 */
	prot.onError = HQ.emptyFn;

	return prot;
}

HQ.ajax.instance = {};
HQ.ajax.counter = 0;
HQ.ajax._errCodeMap = {
	400: {
		msg: 'Bad Request'
	},
	401: {
		msg: 'Unauthorized'
	},
	403: {
		msg: 'Forbidden'
	},
	404: {
		msg: 'Not Found'
	},
	999: {
		msg: 'Proxy page error'
	},
	1000: {
		msg: 'Bad Response'
	},
	1001: {
		msg: 'No Network'
	},
	1002: {
		msg: 'No Data'
	},
	1003: {
		msg: 'Eval Error'
	}
};

/**
 * 跨域发送请求
 * @return {Boolean} 是否成功
 */
HQ.ajax.xsend = function(o, uri){
	if (!(o instanceof HQ.ajax)) {
		return false;
	}

	if (ua.firefox && ua.firefox<3) {
		rt.error("can't surport xsite in firefox!");
		return false;
	}
	function clear(obj){
		try{
			obj._sender = obj._sender.callback = obj._sender.errorCallback = obj._sender.onreadystatechange = null;
		}catch(ignore){}

		if (ua.safari || ua.opera) {
			setTimeout('removeNode($("_xsend_frm_' + obj._name + '"))', 50);
		} else {
			removeNode($("_xsend_frm_" + obj._name));
		}
	}
	
	if (o._sender === null || o._sender === void (0)) {
		var sender = document.createElement("iframe");
		sender.id = "_xsend_frm_" + o._name;
		sender.style.width = sender.style.height = sender.style.borderWidth = "0";
		document.body.appendChild(sender);
		sender.callback = HQ.event.bind(o, function(data){
			o.onSuccess(data);
			clear(o);
		});
		sender.errorCallback = HQ.event.bind(o, function(num){
			o.onError(HQ.ajax._errCodeMap[num]);
			clear(o);
		});
		
		o._sender = sender;
	}
	//获取proxy页面中js库的位置
	var tmp=HQ.config.gbEncoderPath;
	o.GBEncoderPath=tmp?tmp:"";

	o._sender.src = uri.protocol + "://" + uri.host + "/ajax_proxy_gbk.html";
	return true;
}

/**
 * 发送请求
 * @return {Boolean} 是否成功
 */
HQ.ajax.prototype.send = function(){
	if (this._method == 'POST' && this._data == null) {
		rt.warn("HQ.ajax -> {0:q}, can't send data 'null'!", this._name);
		return false;
	}
	var u = new URI(this._uri);
	if (u == null) {
		rt.warn("HQ.ajax -> {0:q}, bad url", this._name);
		return false;
	}
	if (u.host != location.host) {
		return HQ.ajax.xsend(this, u);
	}
	if (this._sender === null || this._sender === void (0)) {
		var sender = tryThese(function(){
			return new XMLHttpRequest();
		}, function(){
			return new ActiveXObject("Msxml2.XMLHTTP");
		}, function(){
			return new ActiveXObject("Microsoft.XMLHTTP");
		}) ||
		null;
		if (!sender) {
			rt.error("HQ.ajax -> {0:q}, create ajax object faild!", this._name);
			return false;
		}
		this._sender = sender;
	}
	
	try {
		this._sender.open(this._method, this._uri, this._isAsync);
	} catch (err) {
		rt.error("exception when opening connection to {0:q}:{1}", this._uri, err);
		return false;
	}
	if (this._method == 'POST' && !this._isHeaderSetted) {
		this._sender.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
		this._isHeaderSetted = true;
	}
	if(this._nc){
		this._sender.setRequestHeader('If-Modified-Since', 'Thu, 1 Jan 1970 00:00:00 GMT');		
		this._sender.setRequestHeader('Cache-Control', 'no-cache');		
	}
	var d = genHttpParamString(this._data);
	
	this._sender.onreadystatechange = HQ.event.bind(this, function(){
		try {
			if (this._sender.readyState == 4) {
				if (this._sender.status >= 200 && this._sender.status < 300) {
					this.onSuccess({
						text: this._sender.responseText,
						xmlDom: this._sender.responseXML
					});
				} else {
					if (ua.safari && (typeof(this._sender.status) == 'undefined')) {
						this.onError(HQ.ajax._errCodeMap[1002]);
					} else {
						this.onError(HQ.ajax._errCodeMap[this._sender.status]);
					}
				}
				delete this._sender;
				this._sender = null;
			}
		} catch (err) {
			rt.error("unknow exception in HQ.ajax.prototype.send()");
		}
	});
	
	this._sender.send(d);
	return true;
};

/**
 * HQ.ajax对象自毁方法，用法 ins=ins.destroy();
 * @return {Object} null用来复写引用本身
 */
HQ.ajax.prototype.destroy = function(){
	var n = this._name;
	delete HQ.ajax.instance[n]._sender;
	HQ.ajax.instance[n]._sender = null;
	delete HQ.ajax.instance[n];
	HQ.ajax.counter--;
	return null;
};
